<?php
/**
 * Description of DatabaseTest
 *
 * @author joona
 */
class Unit_Core_DatabaseTest extends Lib_UnitTestcase
{
    public static function setupBeforeClass()
    {
        Lib_RegistryModifier::backupApplicationINI();
        Lib_RegistryModifier::modifyApplicationINI(
            array(
                'DB_USER = sweatshop' => 'DB_USER = root',
                'DB_PASS = sweatshop' => ';DB_PASS = ',
                'DB_NAME = sweatshop' => 'DB_NAME = test_sweatshop',
                'sweatshop_system.log' => 'sweatshop_system_test.log',
            )
        );
        Lib_QueryWrapper::setUp('root', null, 'test_sweatshop');
        Lib_QueryWrapper::createTestDatabase();
        Lib_QueryWrapper::initializeTestData();
        Core_Registry::reset();

    }

    public static function teardownAfterClass()
    {
        Lib_QueryWrapper::dropTestDatabase();
        Lib_RegistryModifier::returnOriginalApplicationINI();
        Core_Registry::reset();
    }
    
    function setup()
    {
        require_once('Core/Database.php');
        $this->classUnderTest = new Core_Database();
        $this->classUnderTest->connect('localhost', 'root', null, 'test_sweatshop');

    }

    public function test_escateKeysAndValues_single()
    {
         $expectedKeys = array('{sessionID}');
         $expectedValues = array( 111 );

         $this->classUnderTest->setVariable('sessionID', 111, array('type' => 'integer'));
         list($actualKeys, $actualValues) = $this->__callMethod(
             'escapeKeywordsAndValues',array('')
         );
         $this->assertEquals($expectedKeys, $actualKeys);
         $this->assertEquals($expectedValues, $actualValues);
    }

    public function test_escateKeysAndValues_multiple()
    {
         $expectedKeys = array('{id}', '{float}', '{login}');
         $expectedValues = array( 111, 1.23, "'root'");

         $this->classUnderTest->setVariable('id', 111, array());
         $this->classUnderTest->setVariable('float', 1.23, array());
         $this->classUnderTest->setVariable('login', 'root', array());

         list($actualKeys, $actualValues) = $this->__callMethod(
             'escapeKeywordsAndValues',array('')
         );
         $this->assertEquals($expectedKeys, $actualKeys);
         $this->assertEquals($expectedValues, $actualValues);
    }

    public function test_escateKeysAndValues_nullInSelect()
    {
         $expectedKeys = array('{keyword}');
         $expectedValues = array( 'IS NULL' );

         $this->classUnderTest->prepare('SELECT * FROM Something WHERE value = {keyword}');
         $this->classUnderTest->setVariable('keyword', null, array('allowNull' => true));

         list($actualKeys, $actualValues) = $this->__callMethod(
             'escapeKeywordsAndValues',array(true)
         );
         $this->assertEquals($expectedKeys, $actualKeys);
         $this->assertEquals($expectedValues, $actualValues);
    }

    public function test_escateKeysAndValues_nullInInsert()
    {
         $expectedKeys = array('{keyword}');
         $expectedValues = array( 'NULL' );

         $this->classUnderTest->prepare('INSERT INTO Something (someCol) VALUES ({keyword})');
         $this->classUnderTest->setVariable('keyword', null, array('allowNull' => true));

         list($actualKeys, $actualValues) = $this->__callMethod(
             'escapeKeywordsAndValues',array()
         );
         $this->assertEquals($expectedKeys, $actualKeys);
         $this->assertEquals($expectedValues, $actualValues);
    }

    public function test_isSelectClause_true()
    {
        $this->assertTrue(
            $this->__callMethod('isSelectClause', array('SELECT * FROM Bogus'))
        );
    }

    public function test_isSelectClause_withInsert()
    {
        $this->assertFalse($this->__callMethod('isSelectClause', array(
            'INSERT INTO Bogus WHERE something = \'somethingElse\''
        )));
    }

    public function test_isSelectClause_withUpdate()
    {
        $this->assertFalse($this->__callMethod('isSelectClause', array(
            'UPDATE Bogus SET something = \'somethingElse\''
        )));
    }

    public function test_fixIsNulls()
    {
        $input = "SELECT * FROM Somewhere = IS NULL";
        $expected = "SELECT * FROM Somewhere IS NULL";
        $actual = $this->__callMethod('fixIsNulls', array($input));
        $this->assertEquals($expected, $actual);
    }

    public function test_isReadyForExecution_ok()
    {
        $input = "SELECT * FROM Somewhere WHERE A = B";
        $this->assertTrue($this->__callMethod('isReadyForExecution', array($input)));
    }

    public function test_isReadyForExecution_fail()
    {
        $input = "SELECT * FROM Somewhere WHERE A = {b}";
        $this->assertFalse($this->__callMethod('isReadyForExecution', array($input)));
    }

    public function test_reformatQuery_simpleSelect()
    {
        $input = "SELECT * FROM Session where sessionID = {sessionID}";
        $expected = "SELECT * FROM Session where sessionID = 111";

        $this->cut->setVariable('sessionID', 111, array('type' => 'integer'));
        $actual = $this->__callMethod('reformatQuery', array($input));
        $this->assertEquals($expected, $actual);
    }

    public function test_reformatQuery_selectWithNull()
    {
        $input = "SELECT * FROM Session WHERE keyword = {keyword}";
        $expected = "SELECT * FROM Session WHERE keyword IS NULL";

        $this->cut->prepare($input);
        $this->cut->setVariable('keyword', null, array('allowNull' => true));
        $actual = $this->__callMethod('reformatQuery', array($input));
        $this->assertEquals($expected, $actual);
    }

    public function test_reformatQuery_multiSelect()
    {
        $input = 'SELECT * FROM Session where sessionID = {sessionID} AND login = {login} AND date > {startDate}';
        $expected = "SELECT * FROM Session where sessionID = 111 AND login = 'root' AND date > '2011-01-01'";

        $this->cut->setVariable('sessionID', 111, array());
        $this->cut->setVariable('login', 'root', array());
        $this->cut->setVariable('startDate', date('Y-m-d', strtotime('2011-01-01')), array());

        $actual = $this->__callMethod('reformatQuery', array($input));
        $this->assertEquals($expected, $actual);
    }

    public function test_reformatQuery_simpleInsert()
    {
        $input = "INSERT INTO Comment (timestamp, comment) VALUES ({timestamp}, {comment})";
        $expected = "INSERT INTO Comment (timestamp, comment) VALUES ('2011-01-01 12:34:56', 'Bogus comment')";

        $timestamp = '2011-01-01 12:34:56';
        $this->cut->bindVariable('timestamp', $timestamp, array());
        $this->cut->setVariable('comment', 'Bogus comment', array());
        
        $actual = $this->__callMethod('reformatQuery', array($input));
        $this->assertEquals($expected, $actual);
    }

    public function test_reformatQuery_injectionAttempt()
    {
        $input = "SELECT * FROM User WHERE name = {username} AND password = {password}";
        $expected = "SELECT * FROM User WHERE name = 'root' AND password = '\' OR \'\' = \''";

        $this->cut->setVariable('username', 'root', array());
        $this->cut->setVariable('password', "' OR '' = '", array());

        $actual = $this->__callMethod('reformatQuery', array($input));
        $this->assertEquals($expected, $actual);
    }
}